package com.gitee.itembucket.api

import com.gitee.itembucket.ItemBucket
import com.gitee.itembucket.api.event.BucketEvents
import com.gitee.itembucket.api.event.PluginReloadEvent
import com.gitee.itembucket.core.bucket.Bucket
import com.gitee.itembucket.core.bucket.ItemOperationLog
import com.gitee.itembucket.core.bucket.ViolateItem
import com.gitee.itembucket.core.storage.Storage
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Item
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import taboolib.common.LifeCycle
import taboolib.common.platform.Awake
import taboolib.common.platform.Schedule
import taboolib.common.platform.event.SubscribeEvent
import taboolib.common.platform.function.submitAsync
import taboolib.module.nms.getName
import taboolib.platform.util.sendLang

object ItemAPI {

    val violateItems = mutableListOf<ViolateItem>()

    @Awake(LifeCycle.ENABLE)
    fun loadViolates() {
        violateItems.clear()
        violateItems += ItemBucket.config.getStringList("stack-not-put").map {
            ViolateItem(it)
        }
    }

    @SubscribeEvent
    fun e(e: PluginReloadEvent) {
        this.loadViolates()
    }

    @SubscribeEvent
    fun e(e: BucketEvents.Putup) {
        val itemStack = e.item.stack
        if (violateItems.find { it.type.check(itemStack, it.value) } != null) {
            e.isCancelled = true
            e.operator.sendLang("item-un-put",itemStack.getName())
        }
    }

    @Schedule(period = 20, delay = 20, async = false)
    fun autoPickupItem() {
        if (!ItemBucket.isBackpackFullGetEnable) return
        val radius = ItemBucket.backpackFullGetRadius
        Bukkit.getOnlinePlayers().forEach { player ->
            if (player.inventory.firstEmpty() == -1) {
                val entities = player.world.getNearbyEntities(player.location, radius, radius, radius)
                entities.forEach { entity ->
                    if (entity is Item && !entity.isDead && entity.pickupDelay <= 0) {
                        player.inventory.addItem(entity.itemStack).forEach { amount, item ->
                            // 自动放入仓库
                            addItem(player, cloneItem(item,amount))
                            player.sendLang("item-auto-get",item.getName(player),amount)
                        }
                    }
                }
            }
        }
    }

    fun cloneItem(itemStack: ItemStack,amount: Int): ItemStack {
        val stack = itemStack.clone()
        stack.amount = amount
        return stack
    }

    fun addItem(player: Player,itemStack: ItemStack) {
        addItem(player, Bucket.Item(-1,itemStack,itemStack.amount.toLong()))
    }

    fun createPutupItemLog(operator: Player,player: OfflinePlayer,amount: Long,item: Bucket.Item) {
        val itemOperationLog = ItemOperationLog(
            -1L,operator.uniqueId, player.uniqueId, item.id, amount, ItemOperationLog.Type.PUTUP, System.currentTimeMillis()
        )
        submitAsync {
            Storage.INSTANCE.addItemLog(itemOperationLog)
        }
    }

    fun createTakeoutItemLog(operator: Player,player: OfflinePlayer,amount: Long,item: Bucket.Item) {
        val itemOperationLog = ItemOperationLog(
            -1L,operator.uniqueId, player.uniqueId, item.id, amount, ItemOperationLog.Type.TAKEOUT, System.currentTimeMillis()
        )
        submitAsync {
            Storage.INSTANCE.addItemLog(itemOperationLog)
        }
    }

    fun addItem(player: Player,item: Bucket.Item) {
        if (!BucketEvents.Putup(player,player,item).call()) {
            return
        }
        ItemBucket.getBucket(player).thenAccept { bucket ->
            val checkItem = bucket.checkItem(item)
            if (checkItem != -1) {
                val checkValue = bucket.getItem(checkItem)!!
                checkValue.put(item.getAmount())
                submitAsync {
                    ItemBucket.updateItem(player, item)
                    createPutupItemLog(player,player,item.getAmount(),checkValue)
                }
            } else {
                bucket.addItem(item)
                submitAsync {
                    Storage.INSTANCE.createItem(player, item).thenAccept {
                        createPutupItemLog(player,player,item.getAmount(),item)
                    }
                }
            }
        }
    }

}